package br.net.woodstock.tickettoride.api.access.common;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import br.net.woodstock.rockframework.domain.service.ServiceException;
import br.net.woodstock.rockframework.persistence.orm.QueryMetadata;
import br.net.woodstock.rockframework.text.impl.RandomGenerator;
import br.net.woodstock.rockframework.text.impl.RandomGenerator.RandomPattern;
import br.net.woodstock.rockframework.utils.ConditionUtils;
import br.net.woodstock.tickettoride.api.access.UserService;
import br.net.woodstock.tickettoride.api.core.common.AbstractCommonService;
import br.net.woodstock.tickettoride.api.core.utils.Filter;
import br.net.woodstock.tickettoride.api.core.utils.FilterHelper;
import br.net.woodstock.tickettoride.api.core.utils.JPQLHelper;
import br.net.woodstock.tickettoride.api.core.utils.PasswordEncoderHelper;
import br.net.woodstock.tickettoride.api.core.utils.RepositoryHelper;
import br.net.woodstock.tickettoride.orm.User;
import br.net.woodstock.tickettoride.orm.UserStatus;

public abstract class AbstractUserService extends AbstractCommonService implements UserService {

	private static final long	serialVersionUID		= -3134799610709694287L;

	private static final String	JPQL_GET_USER_BY_LOGIN	= "SELECT u FROM User AS u WHERE u.login = :login";

	// private static final String JPQL_GET_USER_BY_LOGIN_PASSWORD =
	// "SELECT u FROM User AS u WHERE u.login = :login AND u.password = :password";

	private static final String	JPQL_LIST_USER_BY_NAME	= "SELECT u FROM User AS u WHERE u.name LIKE :name ORDER BY u.name";

	private static final String	JPQL_LIST_USER_BY_LOGIN	= "SELECT u FROM User AS u WHERE u.login LIKE :login ORDER BY u.name";

	private static final String	JPQL_LIST_USER_BY_EMAIL	= "SELECT u FROM User AS u WHERE u.email LIKE :email ORDER BY u.name";

	private static final Filter	NAME_FILTER				= FilterHelper.getStartWith("NAME");

	private static final Filter	LOGIN_FILTER			= FilterHelper.getStartWith("LOGIN");

	private static final Filter	EMAIL_FILTER			= FilterHelper.getStartWith("EMAIL");

	private RandomGenerator		generator				= new RandomGenerator(8, RandomPattern.LETTER_OR_DIGIT);

	@Override
	public User getById(final Integer id) {
		try {
			return this.getSimpleRepository().get(new User(id));
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}

	@Override
	public User getByLogin(final String login) {
		try {
			Map<String, Object> parameters = new HashMap<String, Object>();
			parameters.put("login", login);
			QueryMetadata metadata = RepositoryHelper.toQueryMetadata(AbstractUserService.JPQL_GET_USER_BY_LOGIN, parameters);
			User user = this.getSimpleQueryableRepository().getSingle(metadata);
			return user;
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}

	@Override
	public User getByLoginPassword(final String login, final String password) {
		try {
			Map<String, Object> parameters = new HashMap<String, Object>();
			parameters.put("login", login);
			QueryMetadata metadata = RepositoryHelper.toQueryMetadata(AbstractUserService.JPQL_GET_USER_BY_LOGIN, parameters);
			User user = this.getSimpleQueryableRepository().getSingle(metadata);
			if ((user != null) && (user.getStatus() == UserStatus.ACTIVE)) {
				String pw = PasswordEncoderHelper.getEncoder().encode(user.getSalt() + password);
				if (user.getPassword().equals(pw)) {
					return user;
				}
			}
			return null;
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}

	@Override
	public void save(final User user) {
		try {
			String salt = this.generator.generate();
			user.setPassword(PasswordEncoderHelper.getEncoder().encode(salt + user.getPassword()));
			user.setSalt(salt);
			user.setStatus(UserStatus.ACTIVE);
			this.getSimpleRepository().save(user);
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}

	@Override
	public void update(final User user) {
		try {
			User u = this.getSimpleRepository().get(user);
			u.setEmail(user.getEmail());
			u.setLogin(user.getLogin());
			u.setName(user.getName());
			u.setStatus(user.getStatus());
			u.setType(user.getType());

			if (ConditionUtils.isNotEmpty(user.getPassword())) {
				u.setPassword(PasswordEncoderHelper.getEncoder().encode(u.getSalt() + user.getPassword()));
			}

			this.getSimpleRepository().update(u);
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}

	@Override
	public void delete(final Integer id) {
		try {
			this.getSimpleRepository().delete(new User(id));
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}

	@Override
	public Collection<User> listByFilter(final String filter) {
		try {
			Map<String, Object> parameters = new HashMap<String, Object>();
			String hql = null;
			if (ConditionUtils.isNotEmpty(filter)) {
				if (AbstractUserService.EMAIL_FILTER.matches(filter)) {
					String email = AbstractUserService.EMAIL_FILTER.getValue(filter);
					parameters.put("email", JPQLHelper.getLikeValue(email, false));
					hql = AbstractUserService.JPQL_LIST_USER_BY_EMAIL;
				} else if (AbstractUserService.LOGIN_FILTER.matches(filter)) {
					String description = AbstractUserService.LOGIN_FILTER.getValue(filter);
					parameters.put("login", JPQLHelper.getLikeValue(description, false));
					hql = AbstractUserService.JPQL_LIST_USER_BY_LOGIN;
				} else if (AbstractUserService.NAME_FILTER.matches(filter)) {
					String name = AbstractUserService.NAME_FILTER.getValue(filter);
					parameters.put("name", JPQLHelper.getLikeValue(name, false));
					hql = AbstractUserService.JPQL_LIST_USER_BY_NAME;
				} else {
					parameters.put("name", JPQLHelper.getLikeValue(filter, false));
					hql = AbstractUserService.JPQL_LIST_USER_BY_NAME;
				}
			} else {
				parameters.put("name", JPQLHelper.getLikeValue(null, false));
				hql = AbstractUserService.JPQL_LIST_USER_BY_NAME;
			}

			QueryMetadata metadata = RepositoryHelper.toQueryMetadata(hql, parameters);
			return this.getSimpleQueryableRepository().getCollection(metadata).getResult();
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}

}
